<template>
  <teleport to=".chat-box">
    <template v-if="isRender">
      <transition name="friends-mark">
        <div class="friends-mark flex" v-show="showDialog">
          <transition name="friends">
            <div class="friends-content" v-show="showDialog">
              <div class="friends-content__header">
                <span>选择朋友</span>
                <SvgIcon
                  icon-class="close"
                  popper-class="title-close"
                  @click="closeDialog"
                />
              </div>
              <div class="friends-content__main">
                <template v-if="showContent">
                  <div class="friends-search">
                    <el-input
                      v-model="seaValue"
                      @input="input(seaValue)"
                      placeholder="请输入备注名"
                    />
                  </div>
                  <el-scrollbar :max-height="350">
                    <ul>
                      <li v-for="[initials, { value }] in currentDatas" :key="initials">
                        <div class="friends-list__initials">{{ initials }}</div>
                        <ul>
                          <li
                            class="friends-list__item"
                            v-for="[key, { avatar, remark }] in value"
                            :key="key"
                            @click="selectPart(key)"
                          >
                            <div
                              :class="{
                                flex: true,
                                'friends-check': true,
                                isChecked: seleIds.has(key),
                                noChecked: !seleIds.has(key),
                              }"
                            >
                              <SvgIcon popper-class="icon-checked" icon-class="check" />
                            </div>
                            <img :src="avatar" alt="" @click.stop="openModal(avatar)" />
                            <span :title="remark">{{ remark }}</span>
                          </li>
                        </ul>
                      </li>
                    </ul>
                  </el-scrollbar>
                  <div class="friends-content__footer">
                    <el-button
                      class="footer-cancel"
                      :disabled="isLoading"
                      @click="closeDialog"
                      >取消</el-button
                    >
                    <el-button
                      class="footer-confirm"
                      type="primary"
                      :disabled="isLoading || !seleIds.size"
                      :loading="isLoading"
                      @click="emits('confirm', userStore.user.userId, [...seleIds])"
                      ><template #loading><Loading /></template>确定</el-button
                    >
                  </div>
                  <Modal v-model="showModal">
                    <img class="img-browser" :src="imgSrc" alt="" /> </Modal
                ></template>
                <div class="main-loading" v-else-if="isRequesting">
                  <SvgIcon icon-class="loadingGray" popper-class="loadingIcon spinMess" />
                </div>
                <div class="main-error" v-else-if="isError">
                  请求失败，点击
                  <span @click="getFriendData">重试</span>
                </div>
              </div>
            </div>
          </transition>
        </div></transition
      ></template
    ></teleport
  >
</template>

<script lang="ts" setup>
import { ref, watch, nextTick, reactive } from "vue";
import { useFriendPinia } from "@/pinia/friend";
import { useUserPinia } from "@/pinia/user";
import Modal from "@/components/ui-components/modal.vue";
import { Base64 } from "js-base64";

const props = defineProps<{
  modelValue: boolean;
  isLoading: boolean;
}>();

const emits = defineEmits<{
  (e: "update:modelValue", show: boolean): void;
  (e: "confirm", selfId: string, otherIds: Array<string>): void;
}>();

const friendStore = useFriendPinia();
const userStore = useUserPinia();

/**
 * 当前用户查看的图片的url
 */
const imgSrc = ref<string>("");
/**
 * 是否显示模态框
 */
const showModal = ref<boolean>(false);
// 浏览图片时打开模态框
const openModal: (url: string) => void = (url: string): void => {
  imgSrc.value = url;
  showModal.value = true;
};

/**
 * 是否正在请求无分组数据
 */
const isRequesting = ref<boolean>(false);
/**
 * 请求是否出错
 */
const isError = ref<boolean>(false);
/**
 * 是否显示正文内容
 */
const showContent = ref<boolean>(false);
/**
 * 所有好友的数据
 */
const friendDatas = ref<Map<string, Friend>>(new Map());
/**
 * 当前所显示的好友的数据
 */
const currentDatas = ref<Map<string, Friend>>(new Map());
/**
 * 展平后的好友数据
 */
const friendDatasFlat = ref<
  {
    initials: string;
    userId: string;
    value: {
      avatar: string;
      remark: string;
    };
  }[]
>([]);

// 请求好友数据
const getFriendData = () => {
  if (!isRequesting.value) {
    if (isError.value) isError.value = false;
    isRequesting.value = true;
    friendStore
      .getAllFriends({ slefId: Base64.encode(userStore.user.userId) })
      .then((res) => {
        isRequesting.value = false;
        if (res.code === 1) {
          for (const [key, value] of res.friendsData) friendDatas.value.set(key, value);
          currentDatas.value = friendDatas.value;
          showContent.value = true;
          for (const [key, value] of res.friendsData)
            for (const [key_, value_] of value.value)
              friendDatasFlat.value.push({
                initials: key,
                userId: key_,
                value: {
                  avatar: value_.avatar,
                  remark: value_.remark,
                },
              });
        } else isError.value = true;
      })
      .catch(() => {
        isRequesting.value = false;
        isError.value = true;
      });
  }
};

/**
 * 是否显示确认操作的对话框
 */
const isRender = ref<boolean>(false);
/**
 * 是否显示确认操作的对话框的内容
 */
const showDialog = ref<boolean>(false);

watch(
  () => props.modelValue,
  (show: boolean) => {
    if (show) {
      isRender.value = true;
      nextTick(() => {
        showDialog.value = true;
        getFriendData();
      });
    } else {
      showDialog.value = false;
      setTimeout(() => {
        isRender.value = false;
        showContent.value = false;
        seleIds.clear();
        seaValue.value = "";
      }, 300);
    }
  },
  { immediate: true }
);

// 是否关闭对话框
const closeDialog = () => {
  if (!props.isLoading && !isRequesting.value) emits("update:modelValue", false);
};

/**
 * 当前用户所勾选的好友账号集合
 */
const seleIds = reactive<Set<string>>(new Set());

// 勾选部分好友
const selectPart = (key: string) => seleIds.delete(key) || seleIds.add(key);

/**
 * 当前用户搜索的值
 */
const seaValue = ref<string>("");
// 输入时触发
const input = (() => {
  let timing: any;
  return (searchValue: string) => {
    if (friendDatas.value.size) {
      if (timing) clearTimeout(timing);
      timing = setTimeout(() => {
        if (!searchValue) {
          seleIds.size && seleIds.clear();
          currentDatas.value = friendDatas.value;
        } else {
          const friendsdatas: Map<string, Friend> = new Map();
          for (const { initials, userId, value } of friendDatasFlat.value)
            if (value.remark.startsWith(searchValue))
              if (friendsdatas.has(initials)) {
                const data = friendsdatas.get(initials);
                data?.value.set(userId, {
                  avatar: value.avatar,
                  remark: value.remark,
                } as any);
              } else
                friendsdatas.set(initials, {
                  value: new Map([
                    [
                      userId,
                      {
                        avatar: value.avatar,
                        remark: value.remark,
                      },
                    ],
                  ]) as any,
                });
          if (friendsdatas.size) currentDatas.value = friendsdatas;
          else currentDatas.value = friendDatas.value;
          seleIds.size && seleIds.clear();
        }
      }, 350);
    }
  };
})();
</script>

<style lang="scss" scoped>
.friends {
  &-enter-active,
  &-leave-active {
    transition: transform 0.3s;
  }

  &-enter-from,
  &-leave-to {
    transform: translateY(-30px);
  }

  &-mark {
    position: fixed;
    inset: 0;
    z-index: 1003;
    @include fade(0.25s, ease);
  }

  &-content {
    background-color: #fff;
    width: 270px;
    border-radius: 6px;
    box-shadow: 0px 0px 6px rgba(0, 0, 0, 0.12);

    &__header {
      position: relative;
      padding: 6px 10px 8px;

      span {
        font-size: 12px;
        color: $dimFontCor;
      }

      .title-close {
        position: absolute;
        right: 3%;
        top: 6px;
        color: #909399;
        cursor: pointer;
        transition: color 0.15s;

        &:hover {
          color: #79bbff;
        }
      }
    }

    &__main {
      padding: 10px 0 8px;
      text-align: center;
      color: #333;

      .main {
        &-loading {
          height: 30px;
          margin-bottom: 18px;

          .loadingIcon {
            font-size: 30px;
          }
        }

        &-error {
          height: 30px;
          font-size: 14px;
          margin-bottom: 18px;

          span {
            transition: color 0.2s;

            &:hover {
              cursor: pointer;
              color: rgb(250, 12, 12);
              text-decoration: underline;
            }
          }
        }
      }
    }

    &__footer {
      padding: 22px 25px 12px;
      .footer {
        &-cancel {
          width: 35%;
        }

        &-confirm {
          width: 35%;
          margin-left: 30%;
        }
      }
    }
  }

  &-list {
    &__item {
      display: flex;
      align-items: center;
      padding: 15px 25px;
      transition: background-color 0.75s;
      font-size: 14px;
      cursor: pointer;

      span {
        display: inline-block;
        max-width: 120px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }

      &:hover {
        background-color: rgba(154, 152, 152, 0.114);
      }

      img {
        @include setWidHei(38px, 38px);
        border-radius: 50%;
        margin-right: 20px;
        object-fit: cover;
      }

      .friends-check {
        @include setWidHei(15px, 15px);
        margin-right: 10%;
        transition: background-color 0.25s;
      }
    }

    &__initials {
      padding: 8px 0 6px 20px;
      color: #8e8e8e;
      text-align: left;
    }
  }

  &-search {
    padding: 5px 18px 15px;
  }
}
</style>
